/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-09-20     refugeer     the first version
 */
#include <rtthread.h>
#include "setup.h"
#include <dfs_file.h>
#include <fal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include "cJSON.h"

#ifndef ULOG_USING_SYSLOG
#define LOG_TAG              "setup"
#define LOG_LVL              LOG_LVL_DBG
#include <ulog.h>
#else
#include <syslog.h>
#endif /* ULOG_USING_SYSLOG */

static const char* kn_touch_min_x = "touch_min_x";
static const char* kn_touch_max_x = "touch_max_x";
static const char* kn_touch_min_y = "touch_min_y";
static const char* kn_touch_max_y = "touch_max_y";

#define FS_PARTITION_NAME  "config"
#define HUODAO_FN    "/123.ini"

static rt_uint32_t read_line(int fd, char* line, rt_uint32_t line_size)
{
    char *pos, *next;
    rt_uint32_t length;

    length = read(fd, line, line_size);
    if (length > 0)
    {
        pos = strstr(line, "\r\n");
        if (pos == RT_NULL)
        {
            pos = strstr(line, "\n");
            next = pos++;
        }
        else
            next = pos + 2;

        if (pos != RT_NULL)
        {
            *pos = '\0';

            /* move back */
            lseek(fd, -(length - (next - line)), SEEK_CUR);

            length = pos - line;
        }
        else
            length = 0;
    }

    return length;
}

static void setup_load_default(void)
{
    struct setup_items setup;

    rt_kprintf("setup_load_default!\r\n");

    setup_save(&setup);
}

void setup_init(void)
{
//    struct rt_device *flash_dev = fal_blk_device_create(FS_PARTITION_NAME);
//    if (flash_dev == NULL)
//    {
//        LOG_E("Can't create a block device on '%s' partition.", FS_PARTITION_NAME);
//    }
//    else
//    {
//        LOG_D("Create a block device on the %s partition of flash successful.", FS_PARTITION_NAME);
//    }
//
//    if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0)
//    {
//        LOG_I("Filesystem initialized!");
//    }
//    else
//    {
//        LOG_D("try to dfs_mkfs: %s", FS_PARTITION_NAME);
//        rt_uint32_t rst = dfs_mkfs("elm", flash_dev->parent.name);
//        if (rst == 0)
//        {
//            LOG_D("dfs_mkfs: %s successful, system will try mount again", FS_PARTITION_NAME);
//            if (dfs_mount(flash_dev->parent.name, "/", "elm", 0, 0) == 0)
//            {
//                LOG_I("Filesystem initialized!");
//            }
//        }
//        else
//        {
//            LOG_E("Failed to initialize filesystem!");
//        }
//    }

    if (dfs_mount("sd0", "/", "elm", 0, 0) == 0)
       {
           LOG_I("Filesystem initialized!");
       }
       else
       {
           LOG_D("try to dfs_mkfs: %s", "sd0");
           rt_uint32_t rst = dfs_mkfs("elm", "sd0");
           if (rst == 0)
           {
               LOG_D("dfs_mkfs: %s successful, system will try mount again", "sd0");
               if (dfs_mount("sd0", "/", "elm", 0, 0) == 0)
               {
                   LOG_I("Filesystem initialized!");
               }
           }
           else
           {
               LOG_E("Failed to initialize filesystem!");
           }
       }
}

rt_err_t setup_load(struct setup_items* setup)
{
    int fd, length;
    char line[64];

    rt_kprintf("setup_load\n");

    fd = open(HUODAO_FN, O_RDONLY, 0);
    if (fd >= 0)
    {
        length = read_line(fd, line, sizeof(line));
        if (strcmp(line, "[config]") == 0)
        {
            char* begin;

            // touch_min_x
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                setup_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_min_x, sizeof(kn_touch_min_x) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->touch_min_x = atoi(begin);
            }

            // touch_max_x
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                setup_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_max_x, sizeof(kn_touch_max_x) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->touch_max_x = atoi(begin);
            }

            // touch_min_y
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                setup_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_min_y, sizeof(kn_touch_min_y) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->touch_min_y = atoi(begin);
            }

            // touch_max_y
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                setup_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_max_y, sizeof(kn_touch_max_y) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->touch_max_y = atoi(begin);
            }
        }
        else
        {
            close(fd);
            setup_load_default();
            return RT_EOK;
        }
    }
    else
    {
        close(fd);
        setup_load_default();
        return -RT_ERROR;
    }

    close(fd);
    return RT_EOK;
}

rt_err_t setup_save(struct setup_items* setup)
{
    int fd, size;
    char* p_str;
    char* buf = rt_malloc(1024);

    if (buf == RT_NULL)
    {
        rt_kprintf("no memory\r\n");
        return RT_ENOMEM;
    }

    p_str = buf;

    fd = open(HUODAO_FN, O_WRONLY | O_TRUNC | O_CREAT, 0);
    if (fd >= 0)
    {
        size = sprintf(p_str, "[config]\r\n"); // [config] sprintf(p_str,"")
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_min_x, setup->touch_min_x); //touch_min_x
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_max_x, setup->touch_max_x); //touch_max_x
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_min_y, setup->touch_min_y); //touch_min_y
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_max_y, setup->touch_max_y); //touch_max_y
        p_str += size;
    }

    size = write(fd, buf, p_str - buf);
    if (size == (p_str - buf))
    {
        rt_kprintf("file write succeed:\r\n");
    }
    else
    {
        rt_kprintf("file write wrong:p_str:%s , buf:%s\r\n", *p_str, *buf);
    }

    close(fd);
    rt_free(buf);

    return RT_EOK;
}

#define PARAM_JSON_FILE_NAME    "/param.json"

int json_param_save(void)
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_address = NULL;

    char* str = NULL;

    cjson_test = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_test, "name", "danyuan1");
    cJSON_AddNumberToObject(cjson_test, "ceng", 8);
    cJSON_AddNumberToObject(cjson_test, "huodao", 10);
    cjson_address = cJSON_CreateObject();
    cJSON_AddNumberToObject(cjson_address, "ceng1_y", 111);
    cJSON_AddNumberToObject(cjson_address, "ceng1_hd1_x", 222);
    cJSON_AddNumberToObject(cjson_address, "ceng1_hd2_x", 333);
    cJSON_AddNumberToObject(cjson_address, "ceng1_hd3_x", 444);
    cJSON_AddNumberToObject(cjson_address, "ceng1_hd4_x", 555);
    cJSON_AddItemToObject(cjson_test, "zuobiao", cjson_address);

    str = cJSON_Print(cjson_test);
    rt_kprintf("%s\n", str);

    int fd, size;

    fd = open(PARAM_JSON_FILE_NAME, O_WRONLY | O_CREAT, 0);

    if (fd > 0)
    {
        rt_kprintf("file open succeed:\r\n");
    }
    else
    {
        rt_kprintf("file open failed:\r\n");
    }
    size = write(fd, str, strlen(str));

    if (size > 0)
    {
        rt_kprintf("file write succeed:\r\n");
    }
    else
    {
        rt_kprintf("file write failed:\r\n");
    }
    close(fd);
    return 0;
}

int json_param_load(void)
{
    cJSON* cjson_test = NULL;
    cJSON* cjson_name = NULL;
    cJSON* cjson_age = NULL;
    cJSON* cjson_weight = NULL;
    cJSON* cjson_address = NULL;
    cJSON* cjson_address_country = NULL;
    cJSON* cjson_address_zipcode = NULL;
//    cJSON* cjson_skill = NULL;
//    cJSON* cjson_student = NULL;
//    int skill_array_size = 0, i = 0;
//    cJSON* cjson_skill_item = NULL;
    char message[200];

//    char *pos, *next;
    int fd, lengh;

    fd = open(PARAM_JSON_FILE_NAME, O_RDONLY, 0);
    rt_kprintf("fd:%d\n", fd);

    lengh = read(fd, message, 200);

    rt_kprintf("lengh:%d\n", lengh);
    /* 解析整段JSO数据 */
    cjson_test = cJSON_Parse(message);
    if (cjson_test == NULL)
    {
        printf("parse fail.\n");
        return -1;
    }

    cjson_name = cJSON_GetObjectItem(cjson_test, "name");
    cjson_age = cJSON_GetObjectItem(cjson_test, "ceng");
    cjson_weight = cJSON_GetObjectItem(cjson_test, "huodao");

    printf("name: %s\n", cjson_name->valuestring);
    printf("ceng:%d\n", cjson_age->valueint);
    printf("huodao:%d\n", cjson_weight->valueint);

    cjson_address = cJSON_GetObjectItem(cjson_test, "zuobiao");
    cjson_address_country = cJSON_GetObjectItem(cjson_address, "ceng1_y");
    cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "ceng1_hd1_x");
    printf("zuobiao-ceng1_y:%d,zuobiao-ceng1_hd1_x:%d\n", cjson_address_country->valueint,
            cjson_address_zipcode->valueint);

//    /* 解析数组 */
//    cjson_skill = cJSON_GetObjectItem(cjson_test, "skill");
//    skill_array_size = cJSON_GetArraySize(cjson_skill);
//    printf("skill:[");
//    for(i = 0; i < skill_array_size; i++)
//    {
//        cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);
//        printf("%s,", cjson_skill_item->valuestring);
//    }
//    printf("\b]\n");
//
//    /* 解析布尔型数据 */
//    cjson_student = cJSON_GetObjectItem(cjson_test, "student");
//    if(cjson_student->valueint == 0)
//    {
//        printf("student: false\n");
//    }
//    else
//    {
//        printf("student:error\n");
//    }

    return 0;
}
